package com.tn.service.map.impl;

import com.alibaba.fastjson.JSONObject;
import com.tn.controller.alarm.common.constants.Constants;
import com.tn.controller.alarm.common.enums.CommonCodeEnum;
import com.tn.controller.alarm.common.model.camera.vo.CameraVO;
import com.tn.controller.alarm.common.model.external.subsystem.vo.ExitPermitVO;
import com.tn.controller.alarm.common.model.external.subsystem.vo.WeighInstructionsVO;
import com.tn.controller.alarm.common.model.map.*;
import com.tn.controller.alarm.common.model.vehicle.entity.TallyTaskInfoDO;
import com.tn.controller.alarm.common.model.vehicle.entity.VehicleInfoDO;
import com.tn.controller.alarm.common.model.vehicle.vo.VehicleWorkWeightVO;
import com.tn.dao.camera.ICameraDao;
import com.tn.dao.map.IMapDao;
import com.tn.dao.vehicle.IVehicleDao;
import com.tn.exception.DatabaseOperationFailedException;
import com.tn.mqtt.MQTTConnect;
import com.tn.service.map.IMapService;
import com.tn.service.rpm.RpmServeService;
import com.tn.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 地图service实现类
 *
 * @program: tn_aucy_java
 * @author: yangjiayao
 * @create: 2022/1/4
 */
@Slf4j
@Service
public class MapServiceImpl implements IMapService {
    /**
     * 地图数据访问层
     */
    private IMapDao mapDao;

    /**
     * 装载车数据访问层
     */
    private IVehicleDao vehicleDao;

    /**
     * 摄像头数据访问层
     */
    private ICameraDao cameraDao;

    /**
     * mqtt消息组件
     */
    private MQTTConnect mqttConnect;

    /**
     * 点位服务
     */
    private RpmServeService rpmServeService;

    /**
     * 注入
     *
     * @param mapDao mapDao
     */
    @Autowired
    public void setMapDao(IMapDao mapDao) {
        this.mapDao = mapDao;
    }

    /**
     * 注入
     *
     * @param vehicleDao vehicleDao
     */
    @Autowired
    public void setVehicleDao(IVehicleDao vehicleDao) {
        this.vehicleDao = vehicleDao;
    }

    /**
     * 注入
     *
     * @param cameraDao cameraDao
     */
    @Autowired
    public void setCameraDao(ICameraDao cameraDao) {
        this.cameraDao = cameraDao;
    }

    /**
     * 注入
     *
     * @param mqttConnect mqttConnect
     */
    @Autowired
    public void setMqttConnect(MQTTConnect mqttConnect) {
        this.mqttConnect = mqttConnect;
    }

    /**
     * 注入
     *
     * @param rpmServeService rpmServeService
     */
    @Autowired
    public void setRpmServeService(RpmServeService rpmServeService) {
        this.rpmServeService = rpmServeService;
    }

    @Override
    public TruckInfoVO queryTruckInfo(String tagId) throws DatabaseOperationFailedException {
        TruckInfoVO truckInfo = mapDao.queryTruckInfo(tagId);
        if (truckInfo == null) {
            throw new DatabaseOperationFailedException(CommonCodeEnum.NOT_EXISTS.getCode(),
                    CommonCodeEnum.NOT_EXISTS.getMessage());
        }
        queryTruckPictureList(truckInfo);
        return truckInfo;
    }

    @Override
    public TruckTrailVO queryTruckTrail(String tagId, Integer truckId) throws DatabaseOperationFailedException {
        TruckInfoVO truckInfo = mapDao.queryTruckInfo(tagId);
        if (truckInfo == null) {
            throw new DatabaseOperationFailedException(CommonCodeEnum.NOT_EXISTS.getCode(),
                    CommonCodeEnum.NOT_EXISTS.getMessage());
        }
        TruckTrailVO trail = new TruckTrailVO(truckInfo);
        trail.setGate(mapDao.queryGateName(trail.getId(), Constants.GATE_IN));
        queryHisPosList(trail, truckInfo);
        queryDestination(trail);
        return trail;
    }

    @Override
    public VehicleInfoVO queryVehicleInfo(String tagId, String position) throws DatabaseOperationFailedException {
        VehicleInfoVO vehicleInfoVO = new VehicleInfoVO();
        // 装载车基本信息
        VehicleInfoDO vehicleInfoDO = mapDao.queryVehicleInfo(tagId);
        if (null != vehicleInfoDO) {
            vehicleInfoVO.setVehicleInfo(vehicleInfoDO);
            // 装货情况
            vehicleInfoVO.setWorkWeight(new VehicleWorkWeightVO(
                    vehicleDao.queryDailyDoneTaskByVehicle(vehicleInfoDO.getId(),
                            DateUtil.dateToString(new Date(), "yyyy-MM-dd")),
                    vehicleDao.queryDailyUndoTaskByVehicle(vehicleInfoDO.getId(),
                            DateUtil.dateToString(new Date(), "yyyy-MM-dd"))));
            // 理货信息
            TallyTaskInfoDO tallyTaskInfoDO = mapDao.queryTallyTaskInfo(vehicleInfoDO.getId());
            if (null != tallyTaskInfoDO) {
                vehicleInfoVO.setTallyTaskInfo(tallyTaskInfoDO);
                // 对应货车信息
                vehicleInfoVO.setTruckInfo(mapDao.queryTruckInfoById(tallyTaskInfoDO.getTruckId()));
            }
        }
        // 摄像头信息
        List<CameraVO> cameraList = cameraDao.queryCameraList();
        if (CollectionUtils.isNotEmpty(cameraList) && position.contains(Constants.POSITION_DIVISION_SYMBOL)) {
            List<CameraVO> matchCamera = cameraList.stream()
                    .filter(camera -> checkInCameraArea(position, camera.getFencePosition()))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(matchCamera)) {
                vehicleInfoVO.setCameraInfo(matchCamera.get(0));
            }
        }
        return vehicleInfoVO;
    }

    @Override
    public void sendWarningToMap(WarningVO warningVO) {
        try {
            mqttConnect.pub(Constants.MQTT.WARNING, JSONObject.toJSONString(warningVO));
        } catch (MqttException e) {
            log.error("Error occurred when send alarm tag mqtt massage to map!");
        }
    }

    @Override
    public void sendGateTagToMap(ExitPermitVO gateInfo) throws MqttException {
        GateTagVO gateTagVO = new GateTagVO(gateInfo);
        gateTagVO.setGoods(mapDao.queryGoods(gateTagVO.getLicense()));
        mqttConnect.pub(Constants.MQTT.GATE_TAG, JSONObject.toJSONString(gateTagVO));
    }

    @Override
    public void sendWeightTagToMap(WeighInstructionsVO weightInfo) throws MqttException {
        WeightTagVO weightTagVO = new WeightTagVO(weightInfo);
        weightTagVO.setGoods(mapDao.queryGoods(weightInfo.getLicense()));
        weightTagVO.setTagId(mapDao.queryTagId(weightInfo.getLicense()));
        mqttConnect.pub(Constants.MQTT.WEIGHT_TAG, JSONObject.toJSONString(weightTagVO));
    }

    /**
     * 查询历史点位
     *
     * @param trail     历史轨迹信息
     * @param truckInfo 车辆信息
     */
    private void queryHisPosList(TruckTrailVO trail, TruckInfoVO truckInfo) {
        Map<String, String[]> hisPos = rpmServeService.queryTraceFetch(truckInfo.getTagId(), truckInfo.getInTime(),
                DateUtil.dateToString(new Date()));
        if (null != hisPos) {
            trail.setHisPosList(sortPos(hisPos));
        }
    }

    /**
     * 解析历史点位数据
     *
     * @param hisPos 历史点位原始数据
     * @return 历史点位
     */
    private List<String> sortPos(Map<String, String[]> hisPos) {
        // 对key（时间戳）进行排序
        List<String> keyArr = new ArrayList<>(hisPos.keySet());
        Collections.sort(keyArr);
        // 根据排序后的key获取点位
        List<String> result = new ArrayList<>();
        for (String keyEle : keyArr) {
            // 将二维点位加入集合
            result.add(hisPos.get(keyEle)[0]);
            // 构造z坐标为0的3维点位
            // result.add(hisPos.get(keyEle)[0] + ",0");
        }
        return result;
    }

    private void queryDestination(TruckTrailVO trail) {
        // TODO
    }

    /**
     * 查询货车图片
     *
     * @param truckInfo 货车信息
     */
    private void queryTruckPictureList(TruckInfoVO truckInfo) {
        truckInfo.setInPicture(mapDao.queryGatePicture(truckInfo.getId(), Constants.GATE_IN));
        truckInfo.setOutPicture(mapDao.queryGatePicture(truckInfo.getId(), Constants.GATE_OUT));
        truckInfo.setTarePicture(mapDao.queryWeightPicture(truckInfo.getId(), Constants.WEIGHING_IN));
        truckInfo.setCarryPicture(mapDao.queryWeightPicture(truckInfo.getId(), Constants.WEIGHING_OUT));
    }

    /**
     * 校验装载车是否在摄像头监控范围
     *
     * @param position      装载车位置
     * @param fencePosition 摄像头围栏
     * @return 是否符合
     */
    private boolean checkInCameraArea(String position, String fencePosition) {
        if (StringUtils.isNotBlank(fencePosition)) {
            String[] positionArr = position.split(Constants.POSITION_DIVISION_SYMBOL);
            double x = Double.parseDouble(positionArr[0]);
            double y = Double.parseDouble(positionArr[1]);
            String[] cameraAreaArr = fencePosition.split(Constants.POSITION_DIVISION_SYMBOL);
            if (cameraAreaArr.length >= 10) {
                double yMin = Double.parseDouble(cameraAreaArr[1]);
                double yMax = Double.parseDouble(cameraAreaArr[10]);
                double xMin = Double.parseDouble(cameraAreaArr[0]);
                double xMax = Double.parseDouble(cameraAreaArr[3]);
                return x > xMin && x < xMax && y > yMin && y < yMax;
            }
        }
        return false;
    }
}
